/*
 * DRI Test Program - 最简单的DRM演示程序
 * 直接调用 /dev/dri/card0 获取设备信息并显示简单图形
 * 
 * 编译: gcc -o dri-test dri-test.c -ldrm
 * 运行: sudo ./dri-test
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <stdint.h>
#include <math.h>
#include <linux/fb.h>

// DRM 基本定义
#define DRM_IOCTL_BASE 'd'
#define DRM_IO(nr) _IO(DRM_IOCTL_BASE, nr)
#define DRM_IOR(nr, type) _IOR(DRM_IOCTL_BASE, nr, type)
#define DRM_IOW(nr, type) _IOW(DRM_IOCTL_BASE, nr, type)
#define DRM_IOWR(nr, type) _IOWR(DRM_IOCTL_BASE, nr, type)

// DRM 版本信息
struct drm_version {
    int version_major;
    int version_minor;
    int version_patchlevel;
    size_t name_len;
    char *name;
    size_t date_len;
    char *date;
    size_t desc_len;
    char *desc;
};

// DRM 模式资源
struct drm_mode_card_res {
    uint64_t fb_id_ptr;
    uint64_t crtc_id_ptr;
    uint64_t connector_id_ptr;
    uint64_t encoder_id_ptr;
    uint32_t count_fbs;
    uint32_t count_crtcs;
    uint32_t count_connectors;
    uint32_t count_encoders;
    uint32_t min_width, max_width;
    uint32_t min_height, max_height;
};

// DRM 连接器信息
struct drm_mode_get_connector {
    uint64_t encoders_ptr;
    uint64_t modes_ptr;
    uint64_t props_ptr;
    uint64_t prop_values_ptr;
    uint32_t count_modes;
    uint32_t count_props;
    uint32_t count_encoders;
    uint32_t encoder_id;
    uint32_t connector_id;
    uint32_t connector_type;
    uint32_t connector_type_id;
    uint32_t connection;
    uint32_t mm_width, mm_height;
    uint32_t subpixel;
    uint32_t pad;
};

// DRM 模式信息
struct drm_mode_modeinfo {
    uint32_t clock;
    uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
    uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
    uint32_t vrefresh;
    uint32_t flags;
    uint32_t type;
    char name[32];
};

// DRM 帧缓冲区创建
struct drm_mode_create_dumb {
    uint32_t height;
    uint32_t width;
    uint32_t bpp;
    uint32_t flags;
    uint32_t handle;
    uint32_t pitch;
    uint64_t size;
};

// DRM 帧缓冲区添加
struct drm_mode_fb_cmd {
    uint32_t fb_id;
    uint32_t width, height;
    uint32_t pitch;
    uint32_t bpp;
    uint32_t depth;
    uint32_t handle;
};

// DRM 内存映射
struct drm_mode_map_dumb {
    uint32_t handle;
    uint32_t pad;
    uint64_t offset;
};

// DRM CRTC 设置
struct drm_mode_crtc {
    uint64_t set_connectors_ptr;
    uint32_t count_connectors;
    uint32_t crtc_id;
    uint32_t fb_id;
    uint32_t x, y;
    uint32_t gamma_size;
    uint32_t mode_valid;
    struct drm_mode_modeinfo mode;
};

// DRM IOCTL 定义
#define DRM_IOCTL_VERSION DRM_IOWR(0x00, struct drm_version)
#define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res)
#define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc)
#define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xA2, struct drm_mode_crtc)
#define DRM_IOCTL_MODE_GETCONNECTOR DRM_IOWR(0xA7, struct drm_mode_get_connector)
#define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd)
#define DRM_IOCTL_MODE_CREATE_DUMB DRM_IOWR(0xB2, struct drm_mode_create_dumb)
#define DRM_IOCTL_MODE_MAP_DUMB DRM_IOWR(0xB3, struct drm_mode_map_dumb)

// 连接状态
#define DRM_MODE_CONNECTED 1
#define DRM_MODE_DISCONNECTED 2

// 全局变量
int drm_fd = -1;
struct drm_mode_card_res resources;
uint32_t connector_id = 0;
uint32_t crtc_id = 0;
struct drm_mode_modeinfo *modes;
struct drm_mode_modeinfo mode;
struct drm_mode_create_dumb create_dumb;
struct drm_mode_fb_cmd fb_cmd;
uint8_t *framebuffer = NULL;

// 错误处理
void error_exit(const char *msg) {
    fprintf(stderr, "错误: %s - %s\n", msg, strerror(errno));
    if (drm_fd >= 0) close(drm_fd);
    exit(1);
}

// 获取DRM版本信息
void get_drm_version() {
    struct drm_version version = {0};
    char name[64] = {0};
    char date[64] = {0};
    char desc[128] = {0};
    
    version.name_len = sizeof(name);
    version.name = name;
    version.date_len = sizeof(date);
    version.date = date;
    version.desc_len = sizeof(desc);
    version.desc = desc;
    
    if (ioctl(drm_fd, DRM_IOCTL_VERSION, &version) < 0) {
        error_exit("获取DRM版本信息失败");
    }
    
    printf("=== DRM 设备信息 ===\n");
    printf("驱动名称: %s\n", name);
    printf("版本: %d.%d.%d\n", version.version_major, version.version_minor, version.version_patchlevel);
    printf("日期: %s\n", date);
    printf("描述: %s\n", desc);
    printf("\n");
}

// 获取显示资源
void get_display_resources() {
    memset(&resources, 0, sizeof(resources));
    
    if (ioctl(drm_fd, DRM_IOCTL_MODE_GETRESOURCES, &resources) < 0) {
        error_exit("获取显示资源失败");
    }
    
    printf("=== 显示资源信息 ===\n");
    printf("帧缓冲区数量: %d\n", resources.count_fbs);
    printf("CRTC数量: %d\n", resources.count_crtcs);
    printf("连接器数量: %d\n", resources.count_connectors);
    printf("编码器数量: %d\n", resources.count_encoders);
    printf("最小分辨率: %dx%d\n", resources.min_width, resources.min_height);
    printf("最大分辨率: %dx%d\n", resources.max_width, resources.max_height);
    printf("\n");
}

// 查找可用的连接器和模式
int find_connector_and_mode() {
    // 安全地分配内存，避免过大分配
    uint32_t max_connectors = resources.count_connectors;
    uint32_t max_crtcs = resources.count_crtcs;
    
    // 限制最大数量以避免内存问题
    if (max_connectors > 32) max_connectors = 32;
    if (max_crtcs > 32) max_crtcs = 32;
    
    uint32_t *connectors = calloc(max_connectors, sizeof(uint32_t));
    uint32_t *crtcs = calloc(max_crtcs, sizeof(uint32_t));
    
    if (!connectors || !crtcs) {
        printf("警告: 内存分配失败，尝试较小的分配\n");
        if (connectors) free(connectors);
        if (crtcs) free(crtcs);
        
        // 尝试较小的分配
        max_connectors = 8;
        max_crtcs = 8;
        connectors = calloc(max_connectors, sizeof(uint32_t));
        crtcs = calloc(max_crtcs, sizeof(uint32_t));
        
        if (!connectors || !crtcs) {
            error_exit("内存分配失败");
        }
    }
    
    // 重新获取资源，使用分配的内存
    struct drm_mode_card_res temp_resources = {0};
    temp_resources.connector_id_ptr = (uint64_t)connectors;
    temp_resources.crtc_id_ptr = (uint64_t)crtcs;
    temp_resources.count_connectors = max_connectors;
    temp_resources.count_crtcs = max_crtcs;
    
    if (ioctl(drm_fd, DRM_IOCTL_MODE_GETRESOURCES, &temp_resources) < 0) {
        printf("获取连接器列表失败\n");
        return -1;
    }
    
    printf("=== 连接器信息 ===\n");
    // 遍历连接器
    for (uint32_t i = 0; i < temp_resources.count_connectors && i < max_connectors; i++) {
        struct drm_mode_get_connector connector = {0};
        connector.connector_id = connectors[i];
        
        if (ioctl(drm_fd, DRM_IOCTL_MODE_GETCONNECTOR, &connector) < 0) {
            printf("获取连接器 %d 信息失败\n", i);
            continue;
        }
        
        printf("连接器 %d: ", i);
        printf("ID=%d, 类型=%d, 状态=%s\n", 
               connector.connector_id, 
               connector.connector_type,
               connector.connection == DRM_MODE_CONNECTED ? "已连接" : "未连接");
        
        if (connector.connection == DRM_MODE_CONNECTED) {
            printf("  ✅ 找到已连接的连接器！\n");
            
            if (connector.count_modes > 0) {
                // 分配模式信息内存
                printf("  可用模式数量: %d\n", connector.count_modes);
                
                // 限制模式数量以避免内存问题
                uint32_t safe_mode_count = connector.count_modes;
                if (safe_mode_count > 100) safe_mode_count = 100;
                
                modes = calloc(safe_mode_count, sizeof(struct drm_mode_modeinfo));
                if (!modes) {
                    printf("  ❌ 内存分配失败\n");
                    continue;
                }
                
                // 重新设置连接器结构体以获取模式
                struct drm_mode_get_connector connector_with_modes = {0};
                connector_with_modes.connector_id = connector.connector_id;
                connector_with_modes.modes_ptr = (uint64_t)modes;
                connector_with_modes.count_modes = safe_mode_count;
                
                if (ioctl(drm_fd, DRM_IOCTL_MODE_GETCONNECTOR, &connector_with_modes) < 0) {
                    printf("  ❌ 获取连接器 %d 模式失败: %s\n", connector.connector_id, strerror(errno));
                    free(modes);
                    continue;
                }
                
                printf("  ✅ 成功获取 %d 个模式\n", connector_with_modes.count_modes);
                
                // 显示前几个可用模式
                printf("  可用模式列表:\n");
                for (uint32_t m = 0; m < connector_with_modes.count_modes && m < 5; m++) {
                    printf("    %d: %s (%dx%d@%dHz)\n", 
                           m, modes[m].name, modes[m].hdisplay, modes[m].vdisplay, modes[m].vrefresh);
                }
                if (connector_with_modes.count_modes > 5) {
                    printf("    ... 还有 %d 个模式\n", connector_with_modes.count_modes - 5);
                }
                
                // 使用第一个可用模式
                if (connector_id == 0) {
                    connector_id = connector.connector_id;
                    mode = modes[0];
                    
                    // 正确获取CRTC ID
                    if (i < temp_resources.count_crtcs) {
                        crtc_id = crtcs[i];
                    } else {
                        printf("  ❗ 使用后备CRTC ID: %d\n", i);
                        crtc_id = i;  // 后备方案
                    }
                    
                    printf("  ✅ 选择模式: %s (%dx%d@%dHz)\n", 
                           mode.name, mode.hdisplay, mode.vdisplay, mode.vrefresh);
                    printf("  ✅ 使用连接器ID: %d, CRTC ID: %d\n", connector_id, crtc_id);
                }
                
                free(modes);
            } else {
                // 如果没有模式，使用默认配置
                printf("  ❗ 连接器 %d 没有可用模式，使用默认配置\n", connector.connector_id);
                if (connector_id == 0) {
                    connector_id = connector.connector_id;
                    if (i < temp_resources.count_crtcs) {
                        crtc_id = crtcs[i];
                    } else {
                        crtc_id = i;  // 后备方案
                    }
                    
                    // 使用默认模式
                    memset(&mode, 0, sizeof(mode));
                    mode.hdisplay = 1024;
                    mode.vdisplay = 768;
                    mode.vrefresh = 60;
                    strcpy(mode.name, "1024x768");
                    
                    printf("  ✅ 使用默认模式: %s (%dx%d@%dHz)\n", 
                           mode.name, mode.hdisplay, mode.vdisplay, mode.vrefresh);
                    printf("  ✅ 使用连接器ID: %d, CRTC ID: %d\n", connector_id, crtc_id);
                }
            }
        }
    }
    
    free(connectors);
    free(crtcs);
    
    if (connector_id == 0) {
        printf("❌ 没有找到可用的连接器\n");
        return -1;
    }
    return 0;
}

// 创建帧缓冲区
void create_framebuffer() {
    // 创建dumb buffer
    printf("=== 创建帧缓冲区 ===\n");
    memset(&create_dumb, 0, sizeof(create_dumb));
    create_dumb.width = mode.hdisplay;
    create_dumb.height = mode.vdisplay;
    create_dumb.bpp = 32; // 32位颜色深度
    
    if (ioctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb) < 0) {
        error_exit("创建dumb buffer失败");
    }
    
    printf("帧缓冲区信息\n");
    printf("大小: %dx%d\n", create_dumb.width, create_dumb.height);
    printf("色深: %d位\n", create_dumb.bpp);
    printf("步长: %d字节\n", create_dumb.pitch);
    printf("总大小: %lu字节\n", create_dumb.size);
    printf("\n");
    
    // 添加帧缓冲区到DRM
    memset(&fb_cmd, 0, sizeof(fb_cmd));
    fb_cmd.width = create_dumb.width;
    fb_cmd.height = create_dumb.height;
    fb_cmd.pitch = create_dumb.pitch;
    fb_cmd.bpp = create_dumb.bpp;
    fb_cmd.depth = 24; // RGB888
    fb_cmd.handle = create_dumb.handle;
    
    if (ioctl(drm_fd, DRM_IOCTL_MODE_ADDFB, &fb_cmd) < 0) {
        error_exit("添加帧缓冲区失败");
    } else {
        printf("帧缓冲区添加成功，ID: %d\n", fb_cmd.fb_id);
    }
}

// 映射帧缓冲区到内存
void map_framebuffer() {
    struct drm_mode_map_dumb map_dumb = {0};
    map_dumb.handle = create_dumb.handle;
    
    if (ioctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb) < 0) {
        error_exit("映射帧缓冲区失败");
    }
    
    framebuffer = mmap(NULL, create_dumb.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd, map_dumb.offset);
    if (framebuffer == MAP_FAILED) {
        error_exit("mmap失败");
    }
    
    printf("帧缓冲区映射成功，地址: %p\n\n", framebuffer);
}

// 绘制简单图形
void draw_graphics() {
    uint32_t *pixels = (uint32_t*)framebuffer;
    uint32_t width = create_dumb.width;
    uint32_t height = create_dumb.height;
    uint32_t pitch = create_dumb.pitch;
    
    printf("=== 绘制图形 ===\n");
    printf("分辨率: %dx%d, 步长: %d字节\n", width, height, pitch);
    
    // 计算实际的像素宽度（以32位像素为单位）
    uint32_t pixel_width = pitch / 4;  // 每行实际像素数
    
    printf("每行像素数: %d (显示宽度: %d)\n", pixel_width, width);
    
    // 清空屏幕为黑色
    memset(framebuffer, 0, create_dumb.size);
    
    // 绘制彩色渐变背景 - 使用正确的步长
    for (uint32_t y = 0; y < height; y++) {
        for (uint32_t x = 0; x < width; x++) {
            uint32_t r = (x * 255) / width;
            uint32_t g = (y * 255) / height;
            uint32_t b = 128;
            
            // 使用BGRA格式（大多数GPU的默认格式）
            uint32_t color = (b << 16) | (g << 8) | r;  // BGR格式
            
            // 使用正确的步长计算像素位置
            pixels[y * pixel_width + x] = color;
        }
    }
    
    // 绘制白色矩形
    uint32_t rect_x = width / 8;
    uint32_t rect_y = height / 4;
    uint32_t rect_w = width / 4;
    uint32_t rect_h = rect_w;
    
    for (uint32_t y = rect_y; y < rect_y + rect_h; y++) {
        for (uint32_t x = rect_x; x < rect_x + rect_w; x++) {
            if (x < width && y < height) {
                pixels[y * pixel_width + x] = 0x0000FF00; // 绿色
            }
        }
    }
    
    // 绘制红色圆形
    uint32_t center_x = width * 3 / 4;
    uint32_t center_y = height / 2;
    uint32_t radius = width / 8;
    
    for (uint32_t y = center_y - radius; y < center_y + radius; y++) {
        for (uint32_t x = center_x - radius; x < center_x + radius; x++) {
            if (x < width && y < height) {
                int dx = x - center_x;
                int dy = y - center_y;
                if (dx*dx + dy*dy <= radius*radius) {
                    pixels[y * pixel_width + x] = 0x000000FF; // 蓝色
                }
            }
        }
    }
    
    // 添加一些测试条纹来验证显示
    printf("添加测试条纹...\n");
    for (uint32_t y = 0; y < 50 && y < height; y++) {
        for (uint32_t x = 0; x < width; x++) {
            if (x % 100 < 50) {
                pixels[y * pixel_width + x] = 0x000000FF; // 蓝色 (RGB格式)
            } else {
                pixels[y * pixel_width + x] = 0x0000FF00; // 绿色 (RGB格式)
            }
        }
    }
    
    printf("已绘制: 彩色渐变背景 + 白色矩形 + 红色圆形 + 测试条纹\n");
    
    // 验证像素数据
    printf("像素验证:\n");
    printf("  左上角 (0,0): 0x%08X\n", pixels[0]);
    printf("  中心 (%d,%d): 0x%08X\n", center_x, center_y, pixels[center_y * pixel_width + center_x]);
    printf("  右下角 (%d,%d): 0x%08X\n", width-1, height-1, pixels[(height-1) * pixel_width + (width-1)]);
}

// 设置CRTC显示图形 - 改进的错误处理版本
void set_crtc() {
    printf("\n🎯 尝试设置CRTC显示图形...\n");
    
    struct drm_mode_crtc crtc = {0};
    crtc.crtc_id = crtc_id;
    crtc.fb_id = fb_cmd.fb_id;  
    crtc.x = 0;
    crtc.y = 0;
    crtc.mode_valid = 1;
    crtc.mode = mode;
    
    // 设置连接器
    uint32_t connectors[] = {connector_id};
    crtc.set_connectors_ptr = (uint64_t)connectors;
    crtc.count_connectors = 1;
    
    printf("📊 CRTC配置信息:\n");
    printf("  CRTC ID: %d\n", crtc.crtc_id);
    printf("  帧缓冲区ID: %d\n", crtc.fb_id);
    printf("  连接器ID: %d\n", connector_id);
    printf("  模式: %s (%dx%d@%dHz)\n", mode.name, mode.hdisplay, mode.vdisplay, mode.vrefresh);
    
    if (ioctl(drm_fd, DRM_IOCTL_MODE_SETCRTC, &crtc) < 0) {
        printf("❌ 设置CRTC失败: %s\n", strerror(errno));
        
        // 分析错误原因
        if (errno == EACCES || errno == EPERM) {
            printf("💡 权限拒绝 - 可能的原因:\n");
            printf("   • 显示管理器（X11/Wayland）正在使用显示设备\n");
            printf("   • 需要停止显示管理器或在虚拟终端中运行\n");
            printf("   • 尝试: sudo systemctl stop gdm (或 lightdm/sddm)\n");
            printf("   • 或者切换到虚拟终端: Ctrl+Alt+F1~F6\n");
        } else if (errno == EBUSY) {
            printf("💡 设备繁忙 - 显示设备被其他程序占用\n");
        } else if (errno == EINVAL) {
            printf("💡 参数无效 - CRTC配置可能不正确\n");
        } else {
            printf("💡 其他错误: %s\n", strerror(errno));
        }
        
        printf("\n🔄 尝试替代方案...\n");
        
        // 尝试不设置连接器
        printf("📋 方案1: 不设置连接器\n");
        crtc.set_connectors_ptr = 0;
        crtc.count_connectors = 0;
        
        if (ioctl(drm_fd, DRM_IOCTL_MODE_SETCRTC, &crtc) == 0) {
            printf("✅ 方案1成功！\n");
            return;
        } else {
            printf("❌ 方案1失败: %s\n", strerror(errno));
        }
        
        // 尝试不设置模式
        printf("📋 方案2: 不设置模式\n");
        crtc.mode_valid = 0;
        crtc.set_connectors_ptr = (uint64_t)connectors;
        crtc.count_connectors = 1;
        
        if (ioctl(drm_fd, DRM_IOCTL_MODE_SETCRTC, &crtc) == 0) {
            printf("✅ 方案2成功！\n");
            return;
        } else {
            printf("❌ 方案2失败: %s\n", strerror(errno));
        }
        
        // 尝试最简配置
        printf("📋 方案3: 最简配置\n");
        memset(&crtc, 0, sizeof(crtc));
        crtc.crtc_id = crtc_id;
        crtc.fb_id = fb_cmd.fb_id;
        
        if (ioctl(drm_fd, DRM_IOCTL_MODE_SETCRTC, &crtc) == 0) {
            printf("✅ 方案3成功！\n");
            return;
        } else {
            printf("❌ 方案3失败: %s\n", strerror(errno));
        }
        
        printf("\n❌ 所有CRTC设置方案都失败了\n");
        printf("🎨 但是帧缓冲区已成功创建，包含您的图形数据！\n");
        printf("💡 在适当的环境中（如纯文本终端），这个程序应该能正常显示图形\n");
        
        return; // 不再退出程序，继续执行
    }
    
    printf("✅ CRTC设置成功，图形已显示！\n");
}

// 尝试通过framebuffer设备显示
void try_framebuffer_display() {
    printf("\n🔄 尝试通过 /dev/fb0 显示图形...\n");
    
    int fb_fd = open("/dev/fb0", O_RDWR);
    if (fb_fd < 0) {
        printf("❌ 无法打开 /dev/fb0: %s\n", strerror(errno));
        return;
    }
    
    // 获取framebuffer信息
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    
    if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo) < 0) {
        printf("❌ 无法获取framebuffer变量信息: %s\n", strerror(errno));
        close(fb_fd);
        return;
    }
    
    if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo) < 0) {
        printf("❌ 无法获取framebuffer固定信息: %s\n", strerror(errno));
        close(fb_fd);
        return;
    }
    
    printf("📺 Framebuffer信息:\n");
    printf("  分辨率: %dx%d\n", vinfo.xres, vinfo.yres);
    printf("  虚拟分辨率: %dx%d\n", vinfo.xres_virtual, vinfo.yres_virtual);
    printf("  色深: %d位\n", vinfo.bits_per_pixel);
    printf("  行长度: %d字节\n", finfo.line_length);
    printf("  内存大小: %d字节\n", finfo.smem_len);
    
    // 映射framebuffer到内存
    size_t fb_size = finfo.smem_len;
    uint8_t *fb_mem = mmap(NULL, fb_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
    
    if (fb_mem == MAP_FAILED) {
        printf("❌ 映射framebuffer失败: %s\n", strerror(errno));
        close(fb_fd);
        return;
    }
    
    printf("✅ Framebuffer映射成功: %p\n", fb_mem);
    
    // 复制我们的图形数据到framebuffer
    uint32_t *fb_pixels = (uint32_t*)fb_mem;
    uint32_t *our_pixels = (uint32_t*)framebuffer;
    
    uint32_t fb_width = vinfo.xres;
    uint32_t fb_height = vinfo.yres;
    uint32_t our_width = create_dumb.width;
    uint32_t our_height = create_dumb.height;
    
    printf("🎨 复制图形数据到framebuffer...\n");
    
    // 计算缩放比例
    uint32_t scale_x = (our_width > fb_width) ? our_width / fb_width : 1;
    uint32_t scale_y = (our_height > fb_height) ? our_height / fb_height : 1;
    
    for (uint32_t y = 0; y < fb_height && y * scale_y < our_height; y++) {
        for (uint32_t x = 0; x < fb_width && x * scale_x < our_width; x++) {
            uint32_t src_x = x * scale_x;
            uint32_t src_y = y * scale_y;
            fb_pixels[y * fb_width + x] = our_pixels[src_y * our_width + src_x];
        }
    }
    
    printf("✅ 图形数据复制完成！\n");
    printf("🎉 如果系统支持，图形应该已经显示在屏幕上了！\n");
    
    // 清理
    munmap(fb_mem, fb_size);
    close(fb_fd);
}

// 清理资源
void cleanup() {
    if (framebuffer && framebuffer != MAP_FAILED) {
        munmap(framebuffer, create_dumb.size);
    }
    if (drm_fd >= 0) {
        close(drm_fd);
    }
}

int main() {
    printf("DRI 测试程序启动\n");
    printf("==================\n\n");
    
    // 尝试打开多个DRM设备
    char drm_device[64];
    int found_device = 0;
    
    for (int i = 0; i < 8; i++) {
        snprintf(drm_device, sizeof(drm_device), "/dev/dri/card%d", i);
        printf("尝试打开 %s...", drm_device);
        
        drm_fd = open(drm_device, O_RDWR);
        if (drm_fd >= 0) {
            printf(" ✅ 成功！\n");
            found_device = 1;
            break;
        } else {
            printf(" ❌ 失败: %s\n", strerror(errno));
        }
    }
    
    if (!found_device) {
        error_exit("无法打开任何DRM设备 (/dev/dri/card0-7)");
    }
    
    printf("\n成功打开 %s\n\n", drm_device);
    
    // 获取设备信息
    get_drm_version();
    get_display_resources();
    find_connector_and_mode();
    
    // 创建和映射帧缓冲区
    create_framebuffer();
    map_framebuffer();
    
    // 绘制图形
    draw_graphics();
    
    // 显示到屏幕
    set_crtc();
    
    // 如果DRM显示失败，尝试framebuffer显示
    //try_framebuffer_display();
    
    printf("\n按任意键退出...\n");
    getchar();
    
    // 清理资源
    cleanup();
    
    printf("程序结束\n");
    return 0;
}